package services

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/xuri/excelize/v2"
	"strconv"
	"time"
	"weiboxs.com/new_h_glasses/models"
	"weiboxs.com/new_h_glasses/utils"
)

type RetailsService struct {
	Archives    *models.Archives      //档案
	Retails     *models.Retails       //零售主表
	RetailsData []*models.RetailsData //零售副表
}

// 获取单据提交的信息
type SerRetail struct {
	AddressName            string  `json:"address_name"`             //邮寄地址
	AssociatorId           int64   `json:"associator_id"`            //档案ID
	Chufang                string  `json:"chufang"`                  //验光处方
	Doctor                 string  `json:"doctor"`                   //医生
	Optometrist            string  `json:"optometrist"`              //验光员
	GoodsData              string  `json:"goods_data"`               //产品信息
	ServeData              string  `json:"serve_data"`               //服务信息
	HopePickUpTime         string  `json:"hope_pick_up_time"`        //取镜日期
	PickUpType             int     `json:"pick_up_type"`             //取镜类型
	OptRemark              string  `json:"optremark"`                //验光备注
	Remark                 string  `json:"remark"`                   //备注
	SalePerson             string  `json:"sale_person"`              //销售人员
	SalePersonId           int64   `json:"sale_person_id"`           //销售ID
	PreferentialTotalPrice float64 `json:"preferential_total_price"` //总优惠销售金额
	SellTotalPrice         float64 `json:"sell_total_price"`         //零售金额
	TotalRealPrice         float64 `json:"total_real_price"`         //实收金额
	CreatedAt              string  `json:"created_at"`               //设置下单时间
}

// 获取产品信息
type GoodsTemp struct {
	Discount    string `json:"discount"`     //折扣
	Snd         string `json:"goods_snd_id"` //产品SND
	Product     string `json:"id"`           //产品ID
	Inventory   string `json:"inventory_id"` //库存ID
	ReserveNum  string `json:"reserve_num"`  //库存数
	SaleNum     string `json:"sale_num"`     //数量
	SellPrirce  string `json:"sell_prirce"`  //零售价
	SinglePrice string `json:"single_price"` //单价
	Subtotal    string `json:"subtotal"`     //小计金额
	Custom      string `json:"custom_id"`    //订制信息
}

// 添加零售单
func InsertRetails(u *models.BackendUser, ret *SerRetail) (int64, error) {

	o := orm.NewOrm()
	to, _ := o.Begin()
	if ret.AssociatorId == 0 {
		return 0, errors.New("没有选择客户")
	}
	arch := &models.Archives{Id: ret.AssociatorId}
	//新增验光数据
	opt := new(models.Optometry)
	if len(ret.Chufang) > 0 {
		opt.DepartmentId = u.DepartmentId
		opt.CreatedAt = time.Now().Unix()
		opt.CreatedBy = u.RealName
		opt.UpdatedBy = u.RealName
		opt.UpdatedAt = time.Now().Unix()
		opt.Archives = arch
		opt.Remarks = ret.OptRemark
		opt.Doctor = ret.Doctor
		opt.Optometrist = ret.Optometrist
		opt.Chufang = ret.Chufang
		opt.DocumentNumber = models.CreateOptometryDocumentNumber(u)
		if _, err := models.OptometryAdd(opt); err != nil {
			to.Rollback()
			return 0, err
		}
	}
	//验光end

	//写入销售单据
	retail := new(models.Retails)
	retail.DepartmentId = u.DepartmentId
	retail.IsPayment = 1
	retail.Archives = arch
	retail.Optometry = opt
	retail.ManualNumber = models.CreateRetailsDocumentNumber(u)
	retail.BusinessName = ret.SalePerson
	retail.TotalMoney = ret.SellTotalPrice
	retail.ChangesMoney = ret.PreferentialTotalPrice
	retail.SumPayable = ret.TotalRealPrice
	retail.Remarks = ret.Remark
	if len(ret.CreatedAt) > 0 {
		retail.CreatedAt = utils.GetDateParse(ret.CreatedAt)
	} else {
		retail.CreatedAt = time.Now().Unix()
	}
	retail.CreatedBy = u.RealName
	retail.UpdatedAt = retail.CreatedAt
	retail.UpdatedBy = retail.CreatedBy
	retail.PickUpType = ret.PickUpType
	retail.HopePickUpTime = utils.GetDateParse(ret.HopePickUpTime)
	retail.AddressName = ret.AddressName
	if _, err := o.Insert(retail); err != nil {
		to.Rollback()
		return 0, err
	}
	//销售单据end

	//写入销售单据明细
	if len(ret.GoodsData) <= 0 {
		to.Rollback()
		return 0, errors.New("请选择商品")
	}
	goods := make([]*GoodsTemp, 0)
	if err := json.Unmarshal([]byte(ret.GoodsData), &goods); err != nil {
		to.Rollback()
		return 0, errors.New("商品解析不正确" + err.Error())
	}
	retail_data := make([]*models.RetailsData, 0)
	for k, _ := range goods {
		g := goods[k]
		sale_num, _ := strconv.ParseInt(g.SaleNum, 10, 64)
		if sale_num == 0 {
			to.Rollback()
			return 0, errors.New("销售商品数量不能为0")
		}
		inventory_id, _ := strconv.ParseInt(g.Inventory, 10, 64)
		custom_id, _ := strconv.ParseInt(g.Custom, 10, 64)
		if inventory_id == 0 && custom_id == 0 {
			to.Rollback()
			return 0, errors.New("库存不存在")
		}

		product_id, _ := strconv.ParseInt(g.Product, 10, 64)
		if product_id == 0 {
			to.Rollback()
			return 0, errors.New("商品不存在")
		}
		original_price, _ := strconv.ParseFloat(g.SellPrirce, 64)
		single_price, _ := strconv.ParseFloat(g.SinglePrice, 64)
		subtotal, _ := strconv.ParseFloat(g.Subtotal, 64)
		discount, _ := strconv.ParseFloat(g.Discount, 64)
		reserve_num, _ := strconv.ParseInt(g.ReserveNum, 10, 64)

		d := new(models.RetailsData)
		d.Retails = retail
		d.Inventory = &models.ErpInventory{Id: inventory_id}
		d.Products = &models.ErpProducts{Id: product_id}
		snd_id, _ := strconv.ParseInt(g.Snd, 10, 64)
		d.Snd = &models.ErpProductsSnd{Id: snd_id}
		d.Amount = sale_num
		d.OriginalPrice = original_price
		d.DiscountRate = discount
		d.UnitPrice = single_price
		d.TotalPrice = subtotal
		d.ReserveNum = reserve_num

		d.Custom = &models.RetailsCustom{Id: custom_id}
		if custom_id > 0 {
			if _, err := o.Raw("UPDATE "+models.RetailsCustomTableName()+" SET retails_id=? WHERE id=?", retail.Id, custom_id).Exec(); err != nil {
				to.Rollback()
				return 0, err
			}
		}
		retail_data = append(retail_data, d)
	}
	if _, err := o.InsertMulti(len(retail_data), retail_data); err != nil {
		to.Rollback()
		return 0, err
	}

	if err := writeRetailsLog(to, retail.Id, "待付款", u); err != nil { //写入销售日志
		to.Rollback()
		return 0, errors.New("销售日志写入失败")
	}

	to.Commit()
	return retail.Id, nil
}

// 更新单据
func UpdateRetails(retails_id int64, u *models.BackendUser, ret *SerRetail) error {

	to, _ := orm.NewOrm().Begin()
	if ret.AssociatorId == 0 {
		return errors.New("没有选择客户")
	}
	//获取单据明细
	retail := new(models.Retails)
	to.QueryTable(models.RetailsTableName()).RelatedSel("Archives", "Optometry").Filter("id", retails_id).One(retail)
	if retail.Id == 0 {
		return errors.New("单据出错")
	}
	arch := retail.Archives

	//新增验光数据
	var opt *models.Optometry
	if len(ret.Chufang) > 0 && retail.Optometry.Id == 0 {
		opt = new(models.Optometry)
		opt.DepartmentId = u.DepartmentId
		opt.CreatedAt = time.Now().Unix()
		opt.CreatedBy = u.RealName
		opt.UpdatedBy = u.RealName
		opt.UpdatedAt = time.Now().Unix()
		opt.Archives = arch
		opt.Remarks = ret.OptRemark
		opt.Doctor = ret.Doctor
		opt.Optometrist = ret.Optometrist
		opt.Chufang = ret.Chufang
		opt.DocumentNumber = models.CreateOptometryDocumentNumber(u)
		if _, err := models.OptometryAdd(opt); err != nil {
			to.Rollback()
			return errors.New("验光单据写入出错" + err.Error())
		}
	} else { //更新验光数据
		opt = retail.Optometry
		opt.Archives = arch
		opt.Remarks = ret.OptRemark
		opt.Doctor = ret.Doctor
		opt.Optometrist = ret.Optometrist
		opt.Chufang = ret.Chufang
		opt.UpdatedBy = u.RealName
		opt.UpdatedAt = time.Now().Unix()
		if err := opt.OptometryEdit(); err != nil {
			to.Rollback()
			return errors.New("验光单据更新出错" + err.Error())
		}
	}
	//验光end

	//更新销售单据
	retail.BusinessName = ret.SalePerson
	retail.TotalMoney = ret.SellTotalPrice
	retail.ChangesMoney = ret.PreferentialTotalPrice
	retail.SumPayable = ret.TotalRealPrice
	retail.Remarks = ret.Remark
	retail.UpdatedAt = retail.CreatedAt
	retail.UpdatedBy = retail.CreatedBy
	retail.PickUpType = ret.PickUpType
	retail.HopePickUpTime = utils.GetDateParse(ret.HopePickUpTime)
	retail.AddressName = ret.AddressName
	if _, err := to.Update(retail); err != nil {
		to.Rollback()
		return errors.New("销售单据更新出错" + err.Error())
	}
	//销售单据end

	//写入销售单据明细
	if len(ret.GoodsData) <= 0 {
		to.Rollback()
		return errors.New("请选择商品")
	}
	goods := make([]*GoodsTemp, 0)
	if err := json.Unmarshal([]byte(ret.GoodsData), &goods); err != nil {
		to.Rollback()
		return errors.New("商品明细解析不正确" + err.Error())
	}
	//清除现有商品后重新写入
	if _, err := to.Raw("DELETE FROM "+models.RetailsDataTableName()+" WHERE retails_id=?", retail.Id).Exec(); err != nil {
		to.Rollback()
		return errors.New("商品明细处理不正确" + err.Error())
	}
	retail_data := make([]*models.RetailsData, 0)
	for k, _ := range goods {
		g := goods[k]
		sale_num, _ := strconv.ParseInt(g.SaleNum, 10, 64)
		if sale_num == 0 {
			to.Rollback()
			return errors.New("销售商品数量不能为0")
		}
		inventory_id, _ := strconv.ParseInt(g.Inventory, 10, 64)
		custom_id, _ := strconv.ParseInt(g.Custom, 10, 64)
		if inventory_id == 0 && custom_id == 0 {
			to.Rollback()
			return errors.New("库存不存在")
		}

		product_id, _ := strconv.ParseInt(g.Product, 10, 64)
		if product_id == 0 {
			to.Rollback()
			return errors.New("商品不存在")
		}
		original_price, _ := strconv.ParseFloat(g.SellPrirce, 64)
		single_price, _ := strconv.ParseFloat(g.SinglePrice, 64)
		subtotal, _ := strconv.ParseFloat(g.Subtotal, 64)
		discount, _ := strconv.ParseFloat(g.Discount, 64)
		reserve_num, _ := strconv.ParseInt(g.ReserveNum, 10, 64)

		d := new(models.RetailsData)
		d.Retails = retail
		d.Inventory = &models.ErpInventory{Id: inventory_id}
		d.Products = &models.ErpProducts{Id: product_id}
		snd_id, _ := strconv.ParseInt(g.Snd, 10, 64)
		d.Snd = &models.ErpProductsSnd{Id: snd_id}
		d.Amount = sale_num
		d.OriginalPrice = original_price
		d.DiscountRate = discount
		d.UnitPrice = single_price
		d.TotalPrice = subtotal
		d.ReserveNum = reserve_num

		d.Custom = &models.RetailsCustom{Id: custom_id}
		if custom_id > 0 {
			if _, err := to.Raw("UPDATE "+models.RetailsCustomTableName()+" SET retails_id=? WHERE id=?", retail.Id, custom_id).Exec(); err != nil {
				to.Rollback()
				return err
			}
		}
		retail_data = append(retail_data, d)
	}
	if _, err := to.InsertMulti(len(retail_data), retail_data); err != nil {
		to.Rollback()
		return err
	}
	if err := writeRetailsLog(to, retail.Id, "更新单据", u); err != nil { //写入销售日志
		to.Rollback()
		return errors.New("销售日志写入失败")
	}
	to.Commit()
	return nil
}

// 获取单据信息
func GetRetailsInfo(retails_id int64, u *models.BackendUser) (map[string]interface{}, error) {
	if retails_id == 0 {
		return nil, errors.New("参数错误")
	}
	ret := make(map[string]interface{})

	o := orm.NewOrm()
	retail := new(models.Retails)
	o.QueryTable(models.RetailsTableName()).RelatedSel("Archives", "Optometry").Filter("id", retails_id).One(retail)
	if retail.Id == 0 {
		return nil, errors.New("单据出错")
	}
	if retail.DepartmentId != u.DepartmentId {
		return nil, errors.New("单据出错")
	}
	ret["retail"] = retail
	//获取单据明细
	ret_data := make([]*models.RetailsData, 0)
	o.QueryTable(models.RetailsDataTableName()).RelatedSel("Products", "Snd", "Inventory__Acceptance").Filter("Retails__Id", retails_id).All(&ret_data)
	ret["retail_data"] = ret_data

	//获取验光数据
	if retail.Optometry.Id > 0 {
		optometry := new(models.Optometry)
		if err := orm.NewOrm().QueryTable(models.OptometryTableName()).Filter("id", retail.Optometry.Id).One(optometry); err != nil {
			return nil, err
		}
		optometry.ChufangData = models.GetOptometryDataList(retail.Optometry.Id)
		ret["optometry"] = optometry
	}
	//获取单据日志
	ret["log"] = models.RetailsLogList(retails_id)

	return ret, nil
}

// 确认付款
type PickUpPaycomfirmData struct {
	AlipayMoney float64                    //支付宝
	WechatMoney float64                    //微信
	CardMoney   float64                    //刷卡
	CashMoney   float64                    //现金
	RetailsId   int64                      //单据ID
	Products    []*PickUpPaycomfirmProduct //产品提货明细
	AddressName string                     //邮递地址
	PostCompany string                     //快递公司
	PostNumber  string                     //快递单号
	PostMoney   float64                    //快递金额
	PostPaytype int                        //快递类型1到付2寄付
	PostUser    string                     //收件人姓名
	PostMobile  string                     //收件人手机
}

// 确认产品数量
type PickUpPaycomfirmProduct struct {
	Id              int64 `json:"id"`
	CollectGoodsNum int64 `json:"collect_goods_num"`
}

func PickUpPaycomfirm(form *PickUpPaycomfirmData, u *models.BackendUser) error {
	if form.RetailsId == 0 {
		return errors.New("单据参数错误")
	}
	if len(form.Products) <= 0 {
		return errors.New("商品参数错误")
	}
	o := orm.NewOrm()
	retail := new(models.Retails)
	o.QueryTable(models.RetailsTableName()).Filter("id", form.RetailsId).One(retail)
	if retail.Id == 0 {
		return errors.New("单据出错")
	}
	if retail.DepartmentId != u.DepartmentId {
		return errors.New("单据出错")
	}

	if retail.IsPayment == 5 || retail.IsPayment == 4 || retail.IsPayment == 3 { //状态为完成、退货、部分退货，不允许处理
		return errors.New("已处理单据不允许操作")
	}
	//获取单据明细
	ret_data := make([]*models.RetailsData, 0)
	o.QueryTable(models.RetailsDataTableName()).RelatedSel("Inventory").Filter("Retails__Id", form.RetailsId).All(&ret_data)

	if retail.PickUpType == 1 { //现场取货
		if err := payTypeForScene(o, retail, ret_data, form, u); err != nil {
			return err
		}
	} else if retail.PickUpType == 2 { //邮递取货
		if err := payTypeForPost(o, retail, ret_data, form, u); err != nil {
			return err
		}
	} else if retail.PickUpType == 3 { //指定日期取货
		if err := payTypeForDate(o, retail, ret_data, form, u); err != nil {
			return err
		}
	}

	return nil
}

// 写销售日志
func writeRetailsLog(o orm.TxOrmer, retail_id int64, content string, u *models.BackendUser) error {
	logErr := models.WriteRetailsLog(o, retail_id, content, u) //现场取镜写入支付金额
	if logErr != nil {                                         //写入销售日志
		return errors.New("销售日志写入失败")
	}
	return nil
}

// 现场提货
func payTypeForScene(o orm.Ormer, retail *models.Retails, retail_data []*models.RetailsData, form *PickUpPaycomfirmData, u *models.BackendUser) error {
	retail.AlipayMoney = form.AlipayMoney
	retail.WechatMoney = form.WechatMoney
	retail.CardMoney = form.CardMoney
	retail.CashMoney = form.CashMoney
	to, _ := o.Begin()
	retail.AlreadyMoney = retail.WechatMoney + retail.CardMoney + retail.CashMoney + retail.AlipayMoney //计算总金额
	if retail.AlreadyMoney != retail.SumPayable {
		return errors.New("现场取镜需要将金额结清")
	}
	retail.IsPayment = 5
	if _, err := to.Update(retail, "AlipayMoney", "WechatMoney", "CardMoney", "CashMoney", "AlreadyMoney", "IsPayment"); err != nil {
		to.Rollback()
		return errors.New("结算出错了")
	}
	for _, d := range retail_data { //判断提货数量
		for _, dd := range form.Products {
			if d.Id == dd.Id {
				d.CollectNum = d.CollectNum + dd.CollectGoodsNum
				if d.CollectNum != d.Amount {
					to.Rollback()
					return errors.New("现场取镜需把货全部提出")
				}
				d.CollectDate = time.Now().Unix()
				if _, err := to.Update(d, "CollectNum", "CollectDate"); err != nil {
					to.Rollback()
					return errors.New("提货出错")
				}
			}
		}
		//处理库存
		if err := cutInventory(to, retail.ManualNumber, d.Inventory, d.Amount); err != nil {
			to.Rollback()
			return err
		}
	}
	//写入支付金额
	if err := writeRetailsLog(to, retail.Id, fmt.Sprintf("支付宝付款：￥%.2f，微信支付：￥ %.2f，现金支付：￥%.2f，银行卡支付：￥%.2f", retail.AlipayMoney, retail.WechatMoney, retail.CashMoney, retail.CardMoney), u); err != nil {
		to.Rollback()
		return err
	}

	to.Commit()
	return nil
}

// 邮递取货
func payTypeForPost(o orm.Ormer, retail *models.Retails, retail_data []*models.RetailsData, form *PickUpPaycomfirmData, u *models.BackendUser) error {
	to, _ := o.Begin()
	if retail.IsPayment == 1 { //待支付状态
		retail.AlipayMoney = form.AlipayMoney
		retail.WechatMoney = form.WechatMoney
		retail.CardMoney = form.CardMoney
		retail.CashMoney = form.CashMoney
		retail.AlreadyMoney = retail.WechatMoney + retail.CardMoney + retail.CashMoney + retail.AlipayMoney //计算总金额
		if retail.AlreadyMoney != retail.SumPayable {
			to.Rollback()
			return errors.New("邮递取镜需要将金额结清")
		}
		retail.IsPayment = 2
		if _, err := to.Update(retail, "AlipayMoney", "WechatMoney", "CardMoney", "CashMoney", "AlreadyMoney", "IsPayment"); err != nil {
			to.Rollback()
			return errors.New("结算出错了")
		}
		//写入支付金额
		if err := writeRetailsLog(to, retail.Id, fmt.Sprintf("支付宝付款：￥%.2f，微信支付：￥ %.2f，现金支付：￥%.2f，银行卡支付：￥%.2f", retail.AlipayMoney, retail.WechatMoney, retail.CashMoney, retail.CardMoney), u); err != nil {
			to.Rollback()
			return err
		}
	} else if retail.IsPayment == 2 { //写入提货信息
		retail.PostCompany = form.PostCompany
		retail.PostMobile = form.PostMobile
		retail.PostMoney = form.PostMoney
		retail.PostNumber = form.PostNumber
		retail.AddressName = form.AddressName
		retail.PostMobile = form.PostMobile
		retail.PostUser = form.PostUser
		retail.PostPaytype = form.PostPaytype
		if len(retail.PostCompany) == 0 || len(retail.PostMobile) == 0 || len(retail.PostNumber) == 0 || len(retail.AddressName) == 0 || len(retail.PostUser) == 0 {
			return errors.New("请完善快递发件信息")
		}
		retail.IsPayment = 5
		if _, err := to.Update(retail, "PostCompany", "PostMobile", "PostMoney", "PostNumber", "AddressName", "PostMobile", "PostUser", "PostPaytype", "IsPayment"); err != nil {
			to.Rollback()
			return errors.New("结算出错了")
		}
		//判断提货数量
		for _, d := range retail_data { //判断提货数量
			for _, dd := range form.Products {
				if d.Id == dd.Id {
					d.CollectNum = d.CollectNum + dd.CollectGoodsNum
					if d.CollectNum != d.Amount {
						to.Rollback()
						return errors.New("提货数与实购实不符")
					}
					d.CollectDate = time.Now().Unix()
					if _, err := to.Update(d, "CollectNum", "CollectDate"); err != nil {
						to.Rollback()
						return errors.New("提货出错")
					}
				}
			}

			if d.Inventory.Id == 0 { //库存ID不存在则获取库存ID
				to.QueryTable(models.ErpInventoryTableName()).Filter("department_id", retail.DepartmentId).Filter("products_id", d.Products.Id).Filter("snd_id", d.Snd.Id).One(d.Inventory)
				if d.Inventory.Id > 0 { //找到了则开始更新库存
					if _, err := to.Update(d, "inventory_id"); err != nil {
						to.Rollback()
						return errors.New("库存提取出错")
					}
				}
			}

			//处理库存
			if err := cutInventory(to, retail.ManualNumber, d.Inventory, d.Amount); err != nil {
				to.Rollback()
				return err
			}
		}
		//记录发货状态
		logErr := writeRetailsLog(to, retail.Id, fmt.Sprintf("已发货，%s：%s", retail.PostCompany, retail.PostNumber), u)
		if logErr != nil { //写入销售日志
			to.Rollback()
			return errors.New("销售日志写入失败")
		}
	}
	to.Commit()
	return nil
}

// 指定日期取货
func payTypeForDate(o orm.Ormer, retail *models.Retails, retail_data []*models.RetailsData, form *PickUpPaycomfirmData, u *models.BackendUser) error {
	to, _ := o.Begin()
	if retail.IsPayment == 1 { //待支付状态
		retail.AlipayMoney = form.AlipayMoney
		retail.WechatMoney = form.WechatMoney
		retail.CardMoney = form.CardMoney
		retail.CashMoney = form.CashMoney
		retail.AlreadyMoney = retail.WechatMoney + retail.CardMoney + retail.CashMoney + retail.AlipayMoney //计算总金额

		retail.IsPayment = 2
		if _, err := to.Update(retail, "AlipayMoney", "WechatMoney", "CardMoney", "CashMoney", "AlreadyMoney", "IsPayment"); err != nil {
			to.Rollback()
			return errors.New("结算出错了")
		}
		if retail.AlreadyMoney > 0 {
			//写入支付金额
			if err := writeRetailsLog(to, retail.Id, fmt.Sprintf("支付宝付款：￥%.2f，微信支付：￥ %.2f，现金支付：￥%.2f，银行卡支付：￥%.2f", retail.AlipayMoney, retail.WechatMoney, retail.CashMoney, retail.CardMoney), u); err != nil {
				to.Rollback()
				return err
			}
		}
	} else if retail.IsPayment == 2 { //写入提货信息
		retail.AlipayMoney += form.AlipayMoney
		retail.WechatMoney += form.WechatMoney
		retail.CardMoney += form.CardMoney
		retail.CashMoney += form.CashMoney
		retail.AlreadyMoney = retail.WechatMoney + retail.CardMoney + retail.CashMoney + retail.AlipayMoney //计算总金额
		if retail.AlreadyMoney != retail.SumPayable {
			to.Rollback()
			return errors.New("支付金额与实付金额不等")
		}
		retail.IsPayment = 5
		if _, err := to.Update(retail, "AlipayMoney", "WechatMoney", "CardMoney", "CashMoney", "AlreadyMoney", "IsPayment"); err != nil {
			to.Rollback()
			return errors.New("结算出错了")
		}
		//判断提货数量
		for _, d := range retail_data { //判断提货数量
			for _, dd := range form.Products {
				if d.Id == dd.Id {
					d.CollectNum = d.CollectNum + dd.CollectGoodsNum
					if d.CollectNum != d.Amount {
						to.Rollback()
						return errors.New("提货数与实购实不符")
					}
					d.CollectDate = time.Now().Unix()
					if _, err := to.Update(d, "CollectNum", "CollectDate"); err != nil {
						to.Rollback()
						return errors.New("提货出错")
					}
				}
			}
			if d.Inventory.Id == 0 { //库存ID不存在则获取库存ID
				to.QueryTable(models.ErpInventoryTableName()).Filter("department_id", retail.DepartmentId).Filter("products_id", d.Products.Id).Filter("snd_id", d.Snd.Id).One(d.Inventory)
				if d.Inventory.Id > 0 { //找到了则开始更新库存
					if _, err := to.Update(d, "inventory_id"); err != nil {
						to.Rollback()
						return errors.New("库存提取出错")
					}
				}
			}
			//处理库存
			if err := cutInventory(to, retail.ManualNumber, d.Inventory, d.Amount); err != nil {
				to.Rollback()
				return err
			}
		}
		//记录发货状态
		if retail.AlreadyMoney > 0 {
			//写入支付金额
			if err := writeRetailsLog(to, retail.Id, fmt.Sprintf("支付宝付款：￥%.2f，微信支付：￥ %.2f，现金支付：￥%.2f，银行卡支付：￥%.2f", retail.AlipayMoney, retail.WechatMoney, retail.CashMoney, retail.CardMoney), u); err != nil {
				to.Rollback()
				return err
			}
		}
		if err := writeRetailsLog(to, retail.Id, "已提货", u); err != nil {
			to.Rollback()
			return err
		}
	}
	to.Commit()
	return nil
}

// 单据作废
func RetailDiscard(sales_id int64) error {
	retail := new(models.Retails)
	retail.Id = sales_id
	if err := orm.NewOrm().Read(retail); err != nil {
		return err
	}
	if retail.IsPayment != 1 {
		return errors.New("不允许操作单据")
	}
	retail.IsPayment = 6
	if _, err := orm.NewOrm().Update(retail, "IsPayment"); err != nil {
		return err
	}
	return nil
}

// 退货数据表
type RefundData struct {
	RetailsId   int64   `form:"sales_id"` //单据ID
	AlipayMoney float64 //支付宝
	WechatMoney float64 //微信
	CashMoney   float64 //现金
	Products    []*struct {
		Id         int64 `form:"id"`         //销售明细ID
		ReturnNum  int64 `form:"returnnum"`  //退货数量
		Collectnum int64 `form:"collectnum"` //可退数量
	} //获取退货商品
}

// 开始退货
func SaveConfirmRefund(refund *RefundData, u *models.BackendUser) error {
	if refund.RetailsId == 0 {
		return errors.New("参数错误")
	}

	//获取原单据信息
	o := orm.NewOrm()
	to, _ := o.Begin()
	source_retail := new(models.Retails)
	o.QueryTable(models.RetailsTableName()).Filter("id", refund.RetailsId).One(source_retail)
	if source_retail.Id == 0 {
		return errors.New("单据出错")
	}
	if source_retail.DepartmentId != u.DepartmentId {
		return errors.New("单据出错")
	}
	//获取原单据明细
	source_ret_data := make([]*models.RetailsData, 0)
	o.QueryTable(models.RetailsDataTableName()).RelatedSel("Inventory").Filter("Retails__Id", refund.RetailsId).All(&source_ret_data)
	if len(source_ret_data) == 0 {
		return errors.New("单据明细出错")
	}
	refund_total_price := refund.CashMoney + refund.WechatMoney + refund.AlipayMoney //计算总退款金额

	//重组单据信息
	refund_retail := new(models.Refunds)
	refund_retail.ManualNumber = models.CreateRefundsDocumentNumber(u)
	refund_retail.RetailsManualNumber = source_retail.ManualNumber
	refund_retail.RetailsId = source_retail.Id
	refund_retail.RetailsTime = source_retail.CreatedAt
	refund_retail.TotalMoney = source_retail.SumPayable //销售实付金额
	refund_retail.SumPayable = refund_total_price
	refund_retail.AlipayMoney = refund.AlipayMoney
	refund_retail.WechatMoney = refund.WechatMoney
	refund_retail.CashMoney = refund.CashMoney
	refund_retail.BusinessName = source_retail.BusinessName
	refund_retail.Archives = source_retail.Archives
	refund_retail.DepartmentId = u.DepartmentId
	refund_retail.CreatedBy = u.RealName
	refund_retail.CreatedAt = time.Now().Unix() //记录销售时间
	refund_retail.UpdatedBy = refund_retail.CreatedBy
	refund_retail.UpdatedAt = refund_retail.CreatedAt

	if _, err := o.Insert(refund_retail); err != nil {
		to.Rollback()
		return errors.New("退货单据保存失败")
	}

	refund_ret_data := make([]*models.RefundsData, 0)
	var total_price float64
	for _, v := range refund.Products {
		for _, vv := range source_ret_data {
			if v.Id == vv.Id && v.ReturnNum > 0 {
				if v.ReturnNum > vv.CollectNum {
					to.Rollback()
					return errors.New("退货数量不能大于可退数量")
				}

				//开始更新原销售明细退货数
				vv.ReturnNum = v.ReturnNum
				if _, err := o.Update(vv, "ReturnNum"); err != nil {
					to.Rollback()
					return errors.New("原销售单退货明细更新失败")
				}

				total_price += float64(v.ReturnNum) * vv.UnitPrice
				retdata := new(models.RefundsData)
				retdata.Products = vv.Products
				retdata.Inventory = vv.Inventory
				retdata.Snd = vv.Snd
				retdata.RetailsDataId = vv.Id
				retdata.Amount = v.ReturnNum
				retdata.DiscountRate = vv.DiscountRate
				retdata.OriginalPrice = vv.OriginalPrice
				retdata.DiscountRate = vv.DiscountRate
				retdata.UnitPrice = vv.UnitPrice
				retdata.Refunds = refund_retail
				retdata.TotalPrice = float64(v.ReturnNum) * vv.UnitPrice
				refund_ret_data = append(refund_ret_data, retdata)
				//处理库存
				if err := addInventory(to, refund_retail.ManualNumber, vv.Inventory, v.ReturnNum); err != nil {
					to.Rollback()
					return err
				}
			}
		}
	}
	if total_price != refund_total_price {
		to.Rollback()
		return errors.New("需退金额不正确")
	}
	if len(refund_ret_data) == 0 {
		to.Rollback()
		return errors.New("没有退货明细数据")
	}

	//判断之前是否还有退货单据
	var sum_money float64
	o.Raw("SELECT SUM(sum_payable) sum_money FROM "+models.RefundsTableName()+" WHERE retails_id=?", source_retail.Id).QueryRow(&sum_money)

	//判断退货状态
	if sum_money == source_retail.SumPayable { //全部退完
		source_retail.IsPayment = 4
		if err := writeRetailsLog(to, source_retail.Id, "全部退货", u); err != nil { //写入销售日志
			to.Rollback()
			return errors.New("销售日志写入失败")
		}
	} else {
		source_retail.IsPayment = 3                                              //部分退货
		if err := writeRetailsLog(to, source_retail.Id, "部分退货", u); err != nil { //写入销售日志
			to.Rollback()
			return errors.New("销售日志写入失败")
		}
	}
	if _, err := o.Update(source_retail, "IsPayment"); err != nil {
		to.Rollback()
		return errors.New("原销售单状态更新失败")
	}
	//写入退货明细数据
	if _, err := o.InsertMulti(len(refund_ret_data), refund_ret_data); err != nil {
		to.Rollback()
		return errors.New("退货明细保存失败")
	}

	to.Commit()
	return nil
}

// 获取退货单据信息
func GetRefundsInfo(retails_id int64, u *models.BackendUser) (map[string]interface{}, error) {
	if retails_id == 0 {
		return nil, errors.New("参数错误")
	}
	ret := make(map[string]interface{})

	o := orm.NewOrm()
	retail := new(models.Refunds)
	o.QueryTable(models.RefundsTableName()).RelatedSel("Archives").Filter("id", retails_id).One(retail)
	if retail.Id == 0 {
		return nil, errors.New("单据出错")
	}
	if retail.DepartmentId != u.DepartmentId {
		return nil, errors.New("单据出错")
	}
	ret["retail"] = retail
	//获取单据明细
	ret_data := make([]*models.RefundsData, 0)
	o.QueryTable(models.RefundsDataTableName()).RelatedSel("Products", "Snd", "Inventory__Acceptance").Filter("Refunds__Id", retails_id).All(&ret_data)
	ret["retail_data"] = ret_data

	return ret, nil
}

// 生成销售数据表格
func RetailsCreateExcel(curuser models.BackendUser, startdate, enddate int64) (string, error) {

	data := models.QueryRetailsTimeSoltSeter(curuser, startdate, enddate)
	if len(data) <= 0 {
		return "", errors.New("没有找到销售数据")
	}

	xlsxData := make([]map[string]string, 0)

	xlsxHeader := map[string]string{"A1": "单号", "B1": "姓名", "C1": "手机号", "D1": "总金额", "E1": "调减金额", "F1": "支付方式", "G1": "支付金额", "H1": "现金", "I1": "营业员", "J1": "确单时间", "K1": "确单人", "L1": "类型", "M1": "支付宝", "N1": "微信", "O1": "刷卡"}

	xlsxData = append(xlsxData, xlsxHeader)

	var i int64 = 1
	var totalMoney float64 = 0.00
	var totalChangesMoney float64 = 0.00
	var totalPaymentMoney float64 = 0.00
	var totalCashMoney float64 = 0.00

	for _, v := range data { //处理数据
		i++
		d := make(map[string]string)

		d[fmt.Sprintf("A%d", i)] = v.ManualNumber
		d[fmt.Sprintf("B%d", i)] = v.Archives.Realname
		d[fmt.Sprintf("C%d", i)] = v.Archives.Mobile
		d[fmt.Sprintf("D%d", i)] = fmt.Sprintf("%0.2f", v.TotalMoney)
		d[fmt.Sprintf("E%d", i)] = fmt.Sprintf("%0.2f", v.ChangesMoney)

		var paytype string = ""

		d[fmt.Sprintf("F%d", i)] = paytype

		d[fmt.Sprintf("G%d", i)] = fmt.Sprintf("%0.2f", v.SumPayable)
		d[fmt.Sprintf("H%d", i)] = fmt.Sprintf("%0.2f", v.CashMoney)
		d[fmt.Sprintf("I%d", i)] = v.BusinessName
		d[fmt.Sprintf("J%d", i)] = utils.GetDateMH(v.CreatedAt)
		d[fmt.Sprintf("K%d", i)] = v.CreatedBy

		d[fmt.Sprintf("L%d", i)] = func(v *models.Retails) string {
			return "销售单"
		}(v)
		d[fmt.Sprintf("M%d", i)] = fmt.Sprintf("%0.2f", v.AlipayMoney)
		d[fmt.Sprintf("N%d", i)] = fmt.Sprintf("%0.2f", v.WechatMoney)
		d[fmt.Sprintf("O%d", i)] = fmt.Sprintf("%0.2f", v.CardMoney)

		totalMoney += v.TotalMoney
		totalChangesMoney += v.ChangesMoney
		totalPaymentMoney += v.SumPayable
		totalCashMoney += v.CashMoney

		xlsxData = append(xlsxData, d)
	}

	//合计数据
	i++
	totalData := map[string]string{}
	totalData[fmt.Sprintf("A%d", i)] = "合计"
	totalData[fmt.Sprintf("D%d", i)] = fmt.Sprintf("%0.2f", totalMoney)
	totalData[fmt.Sprintf("E%d", i)] = fmt.Sprintf("%0.2f", totalChangesMoney)
	totalData[fmt.Sprintf("G%d", i)] = fmt.Sprintf("%0.2f", totalPaymentMoney)
	totalData[fmt.Sprintf("H%d", i)] = fmt.Sprintf("%0.2f", totalCashMoney)

	xlsxData = append(xlsxData, totalData)

	xlsx := excelize.NewFile() //创建表格句柄

	for _, val := range xlsxData { //生成表格行
		if len(val) > 0 {
			for k, v := range val {
				if len(v) > 0 && len(k) > 0 {
					xlsx.SetCellValue("Sheet1", k, v)
				}
			}
		}
	}

	fileName := fmt.Sprintf("./static/download/XS-%s%d.xlsx", time.Now().Format("20060102"), models.CurLoginUserInfo.Id)

	err := xlsx.SaveAs(fileName)

	if err != nil {
		return "", err
	}
	return "/" + fileName, nil
}

// 组合销售曲线数据 数据,总金额,错误
func RetailsTableCurve(curuser models.BackendUser, startdate, enddate int64) (map[string]float64, float64, error) {

	var totalMoney float64 = 0.00

	data := models.QueryRetailsTimeSoltSeter(curuser, startdate, enddate+86400)

	if len(data) <= 0 {
		return nil, totalMoney, errors.New("没有找到销售数据")
	}
	curveData := make(map[string]float64)
	for i := startdate; i <= enddate; i += 86400 { //初始化时间数据
		curveData[time.Unix(i, 0).Format("01-02")] = 0.00
	}

	for _, v := range data { //处理数据
		key := time.Unix(v.CreatedAt, 0).Format("01-02")
		if _, ok := curveData[key]; ok {

			curveData[key] += v.SumPayable
			totalMoney += v.SumPayable
		}
	}
	return curveData, totalMoney, nil
}

// 销售数据分析
func RetailsStatistics(u models.BackendUser, startdate, enddate int64) (map[string]map[string]float64, error) {

	retails := models.QueryRetailsTimeSoltSeter(u, startdate, enddate+86400, "Optometry")
	if len(retails) <= 0 {
		return nil, errors.New("没有找到销售数据")
	}
	statistics := make(map[string]map[string]float64)

	dobusiness := make(map[string]float64) //营业额
	dobusiness["营业金额"] = 0
	dobusiness["销售金额"] = 0
	dobusiness["退货金额"] = 0
	dobusiness["待付金额"] = 0

	sale := make(map[string]float64) //销售
	sale["销售单金额"] = 0
	sale["成交单数"] = 0
	sale["退货金额"] = 0
	sale["退货单数"] = 0
	sale["优惠金额"] = 0

	paytype := make(map[string]float64) //付款方式
	paytype["现金"] = 0
	paytype["支付宝"] = 0
	paytype["微信"] = 0
	paytype["刷卡"] = 0

	salepeople := make(map[string]float64)  //销售人员
	optometrist := make(map[string]float64) //验光师

	for k, _ := range retails {
		//营业额处理，营业金额，销售金额，退货金额，待付金额
		ret := retails[k]
		if ret.IsPayment == 5 || ret.IsPayment == 3 || ret.IsPayment == 4 {
			dobusiness["销售金额"] += ret.AlreadyMoney
		} else {
			dobusiness["待付金额"] += ret.SumPayable
		}
		if ret.IsPayment == 5 || ret.IsPayment == 3 {

			paytype["现金"] += ret.CashMoney
			paytype["支付宝"] += ret.AlipayMoney
			paytype["微信"] += ret.WechatMoney
			paytype["刷卡"] += ret.CardMoney

			sale["销售单金额"] += ret.AlreadyMoney
			sale["优惠金额"] += ret.ChangesMoney

			if _, ok := salepeople[ret.BusinessName]; ok {
				salepeople[ret.BusinessName] += ret.AlreadyMoney
			} else {
				salepeople[ret.BusinessName] = ret.AlreadyMoney
			}
			if ret.Optometry.Id > 0 {
				if _, ok := optometrist[ret.Optometry.Optometrist]; ok {
					optometrist[ret.Optometry.Optometrist] += ret.AlreadyMoney
				} else {
					optometrist[ret.Optometry.Optometrist] = ret.AlreadyMoney
				}
			}
		}

		sale["成交单数"] += 1
	}
	refunds := models.QueryRefundsTimeSoltSeter(u, startdate, enddate+86400)
	for k, _ := range refunds {
		ref := refunds[k]
		dobusiness["退货金额"] += ref.SumPayable
		sale["退货金额"] += ref.SumPayable
		sale["退货单数"] += 1

		paytype["现金"] -= ref.CashMoney
		paytype["支付宝"] -= ref.AlipayMoney
		paytype["微信"] -= ref.WechatMoney

		if _, ok := salepeople[ref.BusinessName]; ok {
			salepeople[ref.BusinessName] -= ref.SumPayable
		} else {
			salepeople[ref.BusinessName] = 0 - ref.SumPayable
		}
	}
	dobusiness["营业金额"] = dobusiness["销售金额"] - dobusiness["退货金额"]
	statistics["dobusiness"] = dobusiness
	statistics["sale"] = sale
	statistics["paytype"] = paytype
	statistics["salepeople"] = salepeople
	statistics["optometrist"] = optometrist

	return statistics, nil
}

// 删除消费信息
func ConfirmDeleteRetails(retails_id int64, u *models.BackendUser) error {
	if retails_id == 0 {
		return errors.New("缺少指定参数")
	}

	to, _ := orm.NewOrm().Begin()

	model := new(models.Retails)
	model.Id = retails_id
	if err := to.Read(model); err != nil {
		return err
	}
	if model.DepartmentId != u.DepartmentId {
		return errors.New("找不到信息")
	}
	if model.IsPayment == 1 {
		return errors.New("已支付，不允许删除")
	}

	//删除主表数据
	if _, err := to.Raw("DELETE FROM "+models.RetailsTableName()+" WHERE id=?", retails_id).Exec(); err != nil {
		to.Rollback()
		return err
	}
	//删除副表
	if _, err := to.Raw("DELETE FROM "+models.RetailsDataTableName()+" WHERE retails_id=?", retails_id).Exec(); err != nil {
		to.Rollback()
		return err
	}
	//判断是否有验光数据，有则同步删除验光数据
	if model.Optometry.Id > 0 {
		if _, err := to.Raw("DELETE FROM "+models.OptometryTableName()+" WHERE id=?", model.Optometry.Id).Exec(); err != nil {
			to.Rollback()
			return err
		}
		//删除验光副表
		if _, err := to.Raw("DELETE FROM "+models.OptometryDataTableName()+" WHERE optometry_id=?", model.Optometry.Id).Exec(); err != nil {
			to.Rollback()
			return err
		}
	}

	//同步删除日志
	if _, err := to.Raw("DELETE FROM "+models.RetailsLogTableName()+" WHERE retails_id=?", retails_id).Exec(); err != nil {
		to.Rollback()
		return err
	}
	//删除定制表
	if _, err := to.Raw("DELETE FROM "+models.RetailsCustomTableName()+" WHERE retails_id=?", retails_id).Exec(); err != nil {
		to.Rollback()
		return err
	}

	to.Commit()
	return nil
}

// 处理订制片
type ExtendErpInventory struct {
	models.ErpInventory
	CustomId int64 `json:"custom_id"`
}

func ConfirmRetailsCustom(product_id int64, eye_type string, u *models.BackendUser) ([]*ExtendErpInventory, error) {

	//获取产品信息
	product, _ := models.GetErpProductsById(product_id, u)
	if product.Id == 0 {
		return nil, errors.New("产品信息出错了")
	}
	//解析度数参数
	custom := make([]*models.RetailsCustom, 0)
	if err := json.Unmarshal([]byte(eye_type), &custom); err != nil {
		return nil, errors.New("光度信息解析出错了")
	}
	to, _ := orm.NewOrm().Begin()
	inventorys := make([]*ExtendErpInventory, 0)
	for k, v := range custom {
		//生成SND
		snd := new(models.ErpProductsSnd)
		snd.Products = product
		snd.Cyl = v.Cyl
		snd.Sph = v.Sph
		snd.Add = v.Add
		if err := models.ErpProductsSndSave(to, snd); err != nil {
			to.Rollback()
			return nil, errors.New("产品属性写入出错")
		}
		//写入价格
		price := new(models.ErpProductsPrice)
		price.Products = product
		price.Department = &models.Department{Id: u.DepartmentId}
		price.CustomSuggestedPrice = v.SuggestedPrice
		price.Snd = snd
		sph, _ := strconv.ParseFloat(v.Sph, 64)
		price.SphMax = sph
		price.SphMin = sph
		cyl, _ := strconv.ParseFloat(v.Cyl, 64)
		price.CylMin = cyl
		price.CylMax = cyl
		if _, err := models.ErpProductsPriceAutoSave(to, price); err != nil {
			to.Rollback()
			return nil, errors.New("定制产品价格写入出错" + err.Error())
		}

		v.Products = product
		if k == 0 {
			v.EyeType = "right"
		} else {
			v.EyeType = "left"
		}
		if _, err := to.Insert(v); err != nil {
			to.Rollback()
			return nil, errors.New("定制信息保存失败" + err.Error())
		}

		extendErpInventory := new(ExtendErpInventory)
		extendErpInventory.CustomId = v.Id
		extendErpInventory.Products = product
		extendErpInventory.Snd = snd
		extendErpInventory.SuggestedPrice = v.SuggestedPrice
		inventorys = append(inventorys, extendErpInventory)
	}
	to.Commit()
	return inventorys, nil
}
